package com.jdone.compus.controller;

import com.jdone.compus.client.HaileIocClient;
import com.jdone.compus.dto.ApiResponse;
import com.jdone.compus.dto.PaymentNotificationRequest;
import com.jdone.compus.dto.RefundResponseDto;
import com.jdone.compus.enums.ChannelType;
import com.jdone.compus.enums.ConsumptionStatus;
import com.jdone.compus.enums.OrderStatus;
import com.jdone.compus.model.BlowUsageRecord;
import com.jdone.compus.model.StudentOrder;
import com.jdone.compus.service.BlowUsageRecordService;
import com.jdone.compus.service.PaymentNotificationService;
import com.jdone.compus.service.RefundService;
import com.jdone.compus.service.StudentOrderService;
import com.jdone.compus.utils.SignUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import javax.persistence.EntityNotFoundException;
import java.math.BigDecimal;
import java.util.*;

/**
 * 支付通知控制器，处理青橄榄支付平台的回调通知。
 */
@RestController
@RequestMapping("/payment")
@Api(value = "回调接口", tags = "回调接口")
public class PaymentNotificationController {

    private static final String MERCHANT_SECRET = "xexpo9zaanpt6onk";  // 替换为您的商户密钥

    //    private static final String CHECK_URL = "https://dev-pay.goliveplus.cn:666/golivepay/check/sign";
    private static final String CHECK_URL = "https://pay.goliveplus.cn:666/golivepay/check/sign";

    @Autowired
    private StudentOrderService studentOrderService;

    @Autowired
    private PaymentNotificationService paymentNotificationService;

    @Autowired
    private BlowUsageRecordService usageService;

    @Autowired
    private HaileIocClient haileIocClient;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private RefundService refundService;


    @PostMapping("/generate")
    @ApiOperation(value = "密匙生成接口", notes = "把需要加密的对象直接传输过来,会返回一个加密好的对象直接使用。直接复制返回的data对象使用")
    public ApiResponse generateSignature(@RequestBody Map<String, String> params) {
        String signature = SignUtil.generateSign(params, MERCHANT_SECRET);

        params.put("sign", signature);

//        System.out.println(params);
        // Return the updated map with the signature included
        return new ApiResponse(true, "Signature generated successfully", params);
    }

    @PostMapping("/notify")
    @ApiOperation("支付回调接口")
    public Map<String, String> handlePaymentNotification(@RequestBody Map<String, String> payload) {

        System.out.println("------  回调接口调用成功 -------");
        Map<String, String> response = new HashMap<>();

        // 1. 签名校验
        Map<String, Object> signResp = checkSign(payload);
        if (signResp == null
                || !(signResp.get("data") instanceof Map<?, ?>)
                || !Boolean.TRUE.equals(((Map<?, ?>) signResp.get("data")).get("signResult"))) {
            response.put("status", "400");
            response.put("msg", "签名校验失败");
            return response;
        }

        // 2. 查订单
        String bizNo = payload.get("out_trade_no");
        BlowUsageRecord record = usageService
                .findByBusinessOrderNo(bizNo)
                .orElseThrow(() -> new EntityNotFoundException("找不到记录: " + bizNo));

        // 3. 重复通知
        if (OrderStatus.PAID.equals(record.getOrderStatus())) {
            response.put("status", "400");
            response.put("msg", "订单已处理");
            return response;
        }

        // 4. 金额校验（分转元）
        BigDecimal callbackAmt = new BigDecimal(payload.get("order_amount"))
                .divide(BigDecimal.valueOf(100));
        if (record.getFee().compareTo(callbackAmt) != 0) {
            response.put("status", "400");
            response.put("msg", "金额不匹配");
            return response;
        }

        record.setOrderStatus(OrderStatus.PAID);
        BlowUsageRecord updated = usageService.update(record.getId(), record);
        // 5. 更新状态
        long seconds = updated.getMinutes() * 60L;
        String channel = updated.getDevice().getChannel() == ChannelType.LEFT ? "01" : "02";
        String cmd = String.format(
                "[{\"Cmd\":\"2D03010101\",\"Value\":{\"Channel\":\"%s\",\"Time\":\"%d\"}}]",
                channel, seconds
        );

        System.out.println("----->> imei" + updated.getDevice().getImei() + "-------->> 请求参数" + cmd);
        // 6. 下发指令
        ApiResponse opResp = haileIocClient.operate(updated.getDevice().getImei(), cmd);
/*        if (!(opResp.getData() instanceof Map<?, ?>)) {
            response.put("status", "400");
            response.put("msg", "设备下发指令失败");
            return response;
        }*/

        response.put("status", "200");
        response.put("msg", "SUCCESS");
//        updated.setOrderStatus(OrderStatus.USED);
//        usageService.update(record.getId(), record);

        return response;
    }


    /**
     * 验证签名。
     *
     * @param data   回调数据
     * @param secret 商户密钥
     * @return 是否通过验证
     */
    private boolean verifySignature(Map<String, String> data, String secret) {
        Map<String, String> sortedData = new TreeMap<>(data);
        StringBuilder dataStr = new StringBuilder();
        sortedData.forEach((k, v) -> {
            if (!"sign".equals(k) && v != null) {
                dataStr.append(k).append("=").append(v).append("&");
            }
        });
        dataStr.append("key=").append(secret);
        String calculatedSign = DigestUtils.md5DigestAsHex(dataStr.toString().getBytes()).toUpperCase();
        return calculatedSign.equals(data.get("sign"));
    }

    public Map<String, Object> checkSign(Map<String, String> payload) {
        // 调用签名校验接口
        Map<String, Object> response = restTemplate.postForObject(CHECK_URL, payload, Map.class);
        return response;
    }


    @ApiOperation("根据业务订单号发起退款")
    @PostMapping("/byBusinessOrderNo")
    public ApiResponse refundByBizNo(
            @RequestParam("businessOrderNo") String businessOrderNo) {
        try {
            String s = refundService.refundByBusinessOrderNo(businessOrderNo);
            return ApiResponse.success(s);
        } catch (Exception ex) {
            return ApiResponse.error(ex.getMessage());
        }
    }
}

